%{

	#include "Controler.hpp"

	extern int yylex (Controler * controler);
%}

%code requires{

	#include <cstddef>
	#include <iostream>
	#include <vector>
	#include <utility>
	typedef std::vector<int> VectorInt;

	#include "Controler.hpp"
	#include "Type.hpp"
	#include "TypeUser.hpp"
	#include "TypeBase.hpp"
	#include "Value.hpp"
	#include "SymbolVar.hpp"
	#include "SymbolConstant.hpp"
	#include "SymbolType.hpp"
	#include "SymbolProg.hpp"
	#include "SymbolFunctProc.hpp"
	#include "Expression.hpp"
	#include "Instruction.hpp"
	#include "CodeContainer.hpp"
	#include "3adCode.hpp"
	typedef std::pair<int, Symbol*> PairIntSymbol;

	#define symbolTablesManager controler->getSymbolTablesManager()
	#define symbolTable controler->getSymbolTablesManager()->getCurrent()
	#define identTable controler->getIdentTable()
	#define expressionsManager controler->getExpressionsManager()

	#define unsupported() controler->errorMsg("Unsupported operation");return 1

}

%lex-param   {class Controler * controler}
%parse-param {class Controler * controler }

%union{
	int id;
	int integer;
	CodeInstruction opCode;

	SymbolFunction * symbolFunction;
	Type * type;
	TypeBase * typeBase;
	Value * value;
	VectorInt * vectorInt;
	ListArguments * listArguments;
	Expression * expression;

	PairIntSymbol * pairIntSymbol;
	SymbolTable * symbolTab;

	CodeContainer * code;
}

%token KW_PROGRAM
%token KW_CONST
%token KW_TYPE
%token KW_VAR
%token KW_ARRAY
%token KW_OF
%token KW_RECORD
%token KW_BEGIN
%token KW_END
%token KW_DIV
%token KW_MOD
%token <opCode> KW_AND
%token <opCode> KW_OR
%token KW_XOR
%token <opCode> KW_NOT
%token KW_IF
%token KW_THEN
%token KW_ELSE
%token KW_WHILE
%token KW_DO
%token KW_REPEAT
%token KW_UNTIL
%token KW_FOR
%token KW_TO
%token KW_DOWNTO
%token KW_PROC
%token KW_FUNC
%token KW_NIL
%token KW_INTEGER
%token KW_REAL
%token KW_BOOLEAN
%token KW_CHAR
%token KW_STRING

%token SEP_SCOL
%token SEP_DOT
%token SEP_DOTS
%token SEP_DOTDOT
%token SEP_COMMA
%token SEP_CO
%token SEP_CF
%token SEP_PO
%token SEP_PF

%token <opCode> OP_EQ
%token <opCode> OP_NEQ
%token <opCode> OP_LT
%token <opCode> OP_LTE
%token <opCode> OP_GT
%token <opCode> OP_GTE
%token <opCode> OP_ADD
%token <opCode> OP_SUB
%token <opCode> OP_MUL
%token <opCode> OP_SLASH
%token <opCode> OP_EXP
%token <opCode> OP_PTR
%token <opCode> OP_AFFECT

%token <id> TOK_IDENT
%token <value> TOK_INTEGER
%token <value> TOK_REAL
%token <value> TOK_BOOLEAN
%token <value> TOK_STRING

%start Program

%nonassoc OP_EQ OP_NEQ OP_GT OP_LT OP_GTE OP_LTE
%left OP_ADD OP_SUB KW_OR KW_XOR
%left OP_MUL OP_SLASH KW_AND KW_DIV KW_MOD
%right KW_NOT OP_NEG OP_POS
%left OP_EXP
%nonassoc OP_PTR
%nonassoc OP_DOT
%left SEP_CO

%nonassoc KW_IFX
%nonassoc KW_ELSE

%type<id> FuncIdent
%type<id> ProcIdent
%type<value> NSInterBase
%type<value> InterBase
%type<vectorInt> ListIdent
%type<type> Type
%type<type> UserType
%type<typeBase> BaseType
%type<type> EnumType
%type<type> ArrayType
%type<type> InterType
%type<type> ArrayIndex
%type<type> ListArrayIndex
%type<type> RecordType
%type<type> PointerType
%type<typeBase> FuncResult
%type<listArguments> ListFormalArgs
%type<listArguments> ValFormalArg
%type<listArguments> VarFormalArg
%type<listArguments> FormalArgs
%type<listArguments> FormalArg
%type<pairIntSymbol> FuncHeader
%type<pairIntSymbol> ProcHeader
%type<vectorInt> RecordField
%type<vectorInt> RecordFields

%type<vectorInt> ListEnumValue


%type<expression> Expression
%type<expression> AtomExpr
%type<expression> BoolExpr
%type<expression> MathExpr
%type<expression> CompExpr
%type<expression> VarExpr
%type<expression> VarExprGaucheAffectation

%type<code> Instr
%type<code> ListInstr
%type<code> BlockCode
%type<code> BlockDeclFunc

%%

Program			:	ProgramHeader SEP_SCOL Block SEP_DOT {
						CodeContainer * code = new CodeContainer;
						code->add(new Instruction(OPCODE_END));
						controler->addToOutputCode(code);
					}
				;

ProgramHeader	:	KW_PROGRAM TOK_IDENT {
						int idIdent = $2;
						symbolTablesManager->push();
						symbolTable->setName( identTable->getName(idIdent) );

						symbolTable->add( $2 , new SymbolProg() );
					}
				;

Block			:	BlockDeclConst BlockDeclType BlockDeclVar BlockDeclFunc BlockCode {
////						controler->addToOutputCode($4)
						controler->addToOutputCode($5);
					}
				;

BlockDeclConst	:	KW_CONST ListDeclConst
			 	|
			 	;

ListDeclConst	:	ListDeclConst DeclConst
			 	|	DeclConst
			 	;

DeclConst		:	TOK_IDENT OP_EQ Expression SEP_SCOL {
						if ($3->isCalculated()) {
							symbolTable->add($1, new SymbolConstant($3));
						} else {
							controler->errorMsg("La valeur de la constante \"" + identTable->getName($1) + " \" ne peut être calculee");
							return 1;
						}
					}
			 	;

BlockDeclType			:	KW_TYPE ListDeclType{
						controler->quitTypeDef();
						if( ! symbolTable->resTempTypes() ) {
							  controler->errorMsg("type inexistent");
								return 1;
						}
					}
			 	|
			 	;

ListDeclType			:	ListDeclType DeclType
			 	|	DeclType
			 	;

DeclType			:	TOK_IDENT OP_EQ Type SEP_SCOL {
						int idIdent = $1;
						Type * type = $3;

						if(symbolTable->getByIdInside(idIdent) != NULL) {
							controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
							return 1;
						}

						symbolTable->add( idIdent , new SymbolType(type) );
					}
			 	;

BlockDeclVar	:	KW_VAR ListDeclVar
			 	|
			 	;

ListDeclVar		:	ListDeclVar DeclVar
			 	|	DeclVar
			 	;

DeclVar			:	ListIdent SEP_DOTS Type SEP_SCOL  {
					 	VectorInt * listIdent = $1;
						Type * type = $3;


					 	for(unsigned int i=0; i< listIdent->size(); i++) {
							int id = (*listIdent)[i];
							if(symbolTable->getByIdInside(id) != NULL) {
							  controler->errorMsg("\""+identTable->getName(id)+"\" deja declare");
								return 1;
							}

							symbolTable->add(id, new SymbolVar(type->clone(), id) );
						}
						delete type;
						delete listIdent;
					}
			 	;

ListIdent			:	ListIdent SEP_COMMA TOK_IDENT {
						VectorInt * listIdent = $1;
						int idIdent = $3;

						listIdent->push_back(idIdent);
						$$ = listIdent;
					}
			 	|	TOK_IDENT {
						VectorInt * listIdent =  new VectorInt;
						int idIdent = $1;

						listIdent->push_back(idIdent);

						$$ = listIdent;
					}
			 	;

BlockDeclFunc	:	ListDeclFunc SEP_SCOL {

					}
			 	| {

			 		}
			 	;

ListDeclFunc			:	ListDeclFunc SEP_SCOL DeclFunc
			 	|	DeclFunc {
						}
			 	;

DeclFunc			:	ProcDecl  {
					 	}
			 	|	FuncDecl {

						}
			 	;

ProcDecl			:	ProcHeader SEP_SCOL Block {
							int idIdent = $1->first;
					 		SymbolProcedure * symbol = (SymbolProcedure * )$1->second;
							delete $1;

							symbolTable->del(idIdent);
							symbolTablesManager->pop();

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);
					 	}
			 	;

ProcHeader		:	ProcIdent  {
							int idIdent = $1;
							ListArguments * listArgs = new ListArguments();

							SymbolProcedure *symbol =  new SymbolProcedure(listArgs);
							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);

							$$ = new PairIntSymbol(idIdent, symbol);
						}
			 	|	ProcIdent FormalArgs {
							int idIdent = $1;
							ListArguments * listArgs = $2;

							SymbolProcedure *symbol =  new SymbolProcedure(listArgs);
							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);

							$$ = new PairIntSymbol(idIdent, symbol);
						}

			 	;

ProcIdent			:	KW_PROC TOK_IDENT {
							int idIdent = $2;

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							//symbolTable->add( idIdent, new Symbol() );
							//TODO : ajouter dans la table de symboles de la procedure,  pour la recursion
							//symbolTablesManager->push();
							symbolTable->setName( identTable->getName(idIdent) );

							$$ = idIdent;
						}
			 	;

FormalArgs			:	SEP_PO ListFormalArgs SEP_PF{
						 $$=$2;
					}
			 	;

ListFormalArgs			:	ListFormalArgs SEP_SCOL FormalArg  {
						ListArguments  * listArgs1 = $1;
						ListArguments  * listArgs2 = $3;
						//TODO: peut etre ici il faut tester que les arguments n-existent encore pas
						int sizeList1 = listArgs1->size();
						for(unsigned int i=0; i<listArgs2->size();i++){
							(*listArgs2)[i]->setPosition(i+sizeList1);
						}
						listArgs1->insert(listArgs1->end(), listArgs2->begin(), listArgs2->end());

						delete listArgs2;
						$$=listArgs1;
					}
			 	|	FormalArg{
						$$=$1;
					}
			 	;

FormalArg			:	ValFormalArg {
						$$=$1;
					}
			 	|	VarFormalArg {
						$$=$1;
					}
			 	;

ValFormalArg			:	ListIdent SEP_DOTS BaseType{
						VectorInt * listIdent = $1;
						TypeBase * type = $3;

						ListArguments  * listArgs = new ListArguments();
						for(unsigned int i=0;i<listIdent->size();i++){
							int idIdent = (*listIdent)[i];
							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}

							//Symbol * sym = symbolTable->getById(idIdent);
							SymbolArgument * symArg =  new SymbolArgument((TypeBase *)type->clone(), ARG_VAL);
							symArg->setPosition(i);


							symbolTable->add(idIdent, symArg);

							listArgs->push_back(symArg);
						}
						
						delete type;
						delete listIdent;
						$$ = listArgs;
					}
				;

VarFormalArg			:	KW_VAR ListIdent SEP_DOTS BaseType {
						VectorInt * listIdent = $2;
						TypeBase * type = $4;

						ListArguments  * listArgs = new ListArguments();
						for(unsigned int i=0;i<listIdent->size();i++){
							int idIdent = (*listIdent)[i];

						//	Symbol * sym = symbolTable->getById(idIdent);
							SymbolArgument * symArg =  new SymbolArgument((TypeBase *)type->clone(), ARG_VAR);
							symArg->setPosition(i);

							symbolTable->substitute(idIdent, symArg);

							listArgs->push_back(symArg);
						}
						delete type;
						delete listIdent;
						$$ = listArgs;
					}
			 	;

FuncDecl			:	FuncHeader SEP_SCOL Block{
							int idIdent = $1->first;
					 		SymbolFunction * symbol = (SymbolFunction * )$1->second;
							delete $1;

							symbolTable->del(idIdent);
							symbolTablesManager->pop();

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);
					 	}
			 	;

FuncHeader		:	FuncIdent FuncResult  {
							int idIdent = $1;
							TypeBase * funcRes = $2;
							ListArguments * listArgs = new ListArguments();

							SymbolFunction *symbol =  new SymbolFunction(funcRes, listArgs);
							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);

							$$ = new PairIntSymbol(idIdent, symbol);
						}
			 	|	FuncIdent FormalArgs FuncResult {
							int idIdent = $1;
							TypeBase * funcRes = $3;
							ListArguments * listArgs = $2;

							SymbolFunction *symbol =  new SymbolFunction(funcRes, listArgs);
							if(symbolTable->getByIdInside(idIdent) != NULL) {
							std::cout << " sdafsdfD"<< std::endl;
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add(idIdent, symbol);

							$$ = new PairIntSymbol(idIdent, symbol);
						}
			 	;

FuncIdent			:	KW_FUNC TOK_IDENT {
							int idIdent = $2;

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							//symbolTable->add( idIdent, new Symbol());
							//TODO : ajouter dans la table de symboles de la procedure,  pour la recursion
							//symbolTablesManager->push();
							symbolTable->setName( identTable->getName(idIdent) );

							$$ = idIdent;
						}
			 	;

FuncResult			:	SEP_DOTS BaseType {
						 	$$ = $2;
						}
			 	;

Type				:	UserType {
							$$ = $1;
						}
			 	|	BaseType {
							$$ = $1;
						}
			 	;

UserType			:	EnumType {
							$$ = $1;
					 	}
			 	|	InterType {
							$$ = $1;
						}
			 	|	ArrayType {
							$$ = $1;
						}
			 	|	RecordType {
							$$ = $1;
						}
			 	|	PointerType {
							$$ = $1;
						}
			 	;

BaseType			:	TOK_IDENT {
					 		int idIdent = $1;

							$$=NULL;
					 		Symbol * symbol = symbolTable->getById(idIdent);
							if(symbol == NULL){
								if(controler->isInTypeDef()){
									$$ = symbolTable->nextTempType(idIdent);
								} else{
									controler->errorMsg("\""+identTable->getName(idIdent)+"\" n'a pas ete declare");
									return 1;
								}
							}
							if($$==NULL && SymbolType() != *symbol ) {
								controler->errorMsg("\""+identTable->getName(idIdent)+"\" n'est pas un type");
								return 1;
							}
							/*
							if( ! symbol->getType()->isOfBaseType() ) {
								controler->errorMsg("\""+identTable->getName(idIdent)+"\" n'est pas un type de base ");
								return 1;
							}
							*/
							if($$==NULL){
								$$ = (TypeBase *) symbol->getType()->clone();
							}


							//symbolTable->add( $1, new Symbol() );
						}
				|   KW_INTEGER {
					 		$$ = new TypeInteger();
						}
				|	KW_REAL {
					 		$$ = new TypeReal();
						}
				|	KW_BOOLEAN{
					 		$$ = new TypeBoolean();
						}
				|	KW_CHAR {
					 		$$ = new TypeChar();
						}
				|	KW_STRING {
					 		$$ = new TypeString();
						}
				;

EnumType			:	SEP_PO ListEnumValue SEP_PF{
							ListEnumValues *listEnumVal = $2;
							TypeEnum * enumeration;

					 		enumeration =new TypeEnum(listEnumVal, identTable);

							for(unsigned int i=0;i<listEnumVal->size();i++) {
								int idIdent = (*listEnumVal)[i];
								symbolTable->substitute( idIdent, new SymbolValEnum(enumeration,i) );
							}
							$$ = enumeration;
					  }
			 	;

ListEnumValue			:	ListEnumValue SEP_COMMA TOK_IDENT {
							int idIdent = $3;
							ListEnumValues *listEnumVal = $1;

							listEnumVal->push_back(idIdent);

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add( idIdent, new Symbol() );


							$$ = listEnumVal;
						}
			 	|	TOK_IDENT {
							int idIdent = $1;
							ListEnumValues *listEnumVal = new ListEnumValues();

							listEnumVal->push_back(idIdent);

							if(symbolTable->getByIdInside(idIdent) != NULL) {
							  controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare");
								return 1;
							}
							symbolTable->add( idIdent , new Symbol() );

							$$ = listEnumVal;
						}
			 	;

InterType			:	InterBase SEP_DOTDOT InterBase{
							Value * minInterVal = $1;
							Value * maxInterVal = $3;

							if(minInterVal )
							if(minInterVal->getValType() != maxInterVal->getValType()){
							  controler->errorMsg("les 2 bornes de l'interval n'on pas le meme type");
								return 1;
							}
							//TODO : interval de type != int
							if(minInterVal->getInteger() > maxInterVal->getInteger()){
							  controler->errorMsg("la borne inferieure de l'interval doit etre plus petite que la borne superieure");
								return 1;
							}
							$$ = new TypeInter(minInterVal->getInteger(), maxInterVal->getInteger(), new TypeInteger());
						}
			 	;

InterBase			:	NSInterBase {
							$$ = $1;
						}
			 	|	OP_SUB NSInterBase {
							//TODO: Type != entier
							$$ = new Value( - $2->getInteger());
							delete $2;
						}
			 	;

NSInterBase			:	TOK_IDENT {
							Symbol * symbol = symbolTable->getById($1);
							if (symbol == NULL) {
							  controler->errorMsg("symbole non-declare");
								return 1;
							}
							if (! symbol->hasValue() ) {
							  controler->errorMsg("borne incorrecte");
								return 1;
							}
							if (! symbol->getValue()->isIntervalLimit() ){
							  controler->errorMsg("borne de type incompatible");
								return 1;
							}
							$$=symbol->getValue()->clone();
						}
			 	|	TOK_INTEGER {
							$$ = $1;
						}
			 	;

ArrayType			:	KW_ARRAY SEP_CO ListArrayIndex SEP_CF KW_OF Type {
							TypeArrayIndexList * indexList = (TypeArrayIndexList *) $3;
							Type * typeOfElements = $6;
							if (TypeTemp() == *typeOfElements){
							  controler->errorMsg("type incorrecte pour les elements du tableau");
								return 1;
							}
							$$ = new TypeArray( typeOfElements, indexList);
						}
			 	;

ListArrayIndex			:	ListArrayIndex SEP_COMMA ArrayIndex {
							TypeInter * interval = (TypeInter *) $3;
							TypeArrayIndexList * indexList = (TypeArrayIndexList *) $1;

							indexList->addInter( interval );

							$$ = indexList;
						}
				|	ArrayIndex {
							TypeInter * interval = (TypeInter *) $1;
							TypeArrayIndexList * indexList = new TypeArrayIndexList;

							indexList->addInter( interval );

							$$ = indexList;
						}
				;

ArrayIndex			:	TOK_IDENT {

						 //identifiant deja existant, de type interval
						 //TODO: erreur quand l'identifiant n'est pas de type interval

					 		int idIdent = $1;

					 		Symbol * symbol = symbolTable->getById(idIdent);
							bool badType = false;
							if (symbol->getType() == NULL) {
								badType = true;
							}
							if(badType){
							  controler->errorMsg("le tableau doit etre indexe par des intervales");
								return 1;
							}

					 		$$ = symbol->getType()->clone();

						}
			 	|	InterType {
							$$ = $1;
						}
			 	;

RecordType			:	KW_RECORD RecordFields KW_END {
							VectorInt * listIdent = $2;
							
							symbolTable->setName( "type_record" );
							$$ = new TypeRecord(listIdent, symbolTable, identTable);
							//TODO:fuite memoire due a l'absence du destructeur dans record,  due 
							//au fait que clone() de record renvoie l'objet this
							symbolTablesManager->pop();
						}

			 	;

RecordFields			:	RecordFields SEP_SCOL RecordField{

							VectorInt * listIdent1 = $1;
							VectorInt * listIdent2 = $3;
							listIdent1->insert(listIdent1->end(), listIdent2->begin(), listIdent2->end());

							delete listIdent2;
							$$=listIdent1;
						}
			 	|	RecordField {
							$$=$1;
						}
			 	;

RecordField			:	ListIdent SEP_DOTS Type {
							VectorInt * listIdent = $1;
							Type * type = $3;
							//SymbolTable * symTabRecord = new SymbolTable();

							if (TypeTemp() == *type){
							  controler->errorMsg("type incorrecte pour les elements du record");
								return 1;
							}
							for(unsigned int i=0; i< listIdent->size(); i++) {
								int idIdent = (*listIdent)[i];

								if(symbolTable->getByIdInside(idIdent) != NULL) {
									controler->errorMsg("\""+identTable->getName(idIdent)+"\" deja declare dans le record");
									exit(1);
								}

								symbolTable->add(idIdent, new SymbolRecord( type->clone() , i) );
							}

							delete type;
							$$=listIdent;
						}

PointerType			:	OP_PTR Type{
							Type * type = $2;
							/*if(TypeTemp() == * type){
								$$=type;
							}else {*/
								$$ = new TypePointer(type);

						}
			 	;

BlockCode		:	KW_BEGIN ListInstr KW_END {
						$$ = $2;
					}
				|	KW_BEGIN ListInstr SEP_SCOL KW_END {
						$$ = $2;
					}
				|	KW_BEGIN KW_END {
						$$ = new CodeContainer();
					}
			 	;

ListInstr		:	ListInstr SEP_SCOL Instr {
						$$ = $1;
						$$->add($3);
					}
			 	|	Instr {
			 			$$ = $1;
					}
			 	;

Instr			:	KW_WHILE Expression KW_DO Instr {
			 			unsupported();
					}
			 	|	KW_REPEAT ListInstr KW_UNTIL Expression {
			 			unsupported();
					}
			 	|	KW_FOR TOK_IDENT OP_AFFECT Expression ForDirection Expression KW_DO Instr {
					//		symbolTable->add( $2, new Symbol() );
						}
			 	|	KW_IF Expression KW_THEN Instr %prec KW_IFX {
			 			unsupported();
					}
			 	|	KW_IF Expression KW_THEN Instr KW_ELSE Instr {
			 			unsupported();
					}
			 	|	VarExprGaucheAffectation OP_AFFECT Expression {

			 			//TODO expressionsManager->opAffectation();
			 			Operand * opDroite;
			 			Instruction * instRes;
			 			if ($3->getCode() == NULL) {
			 				$$ = new CodeContainer();
			 			} else {
							$$ = $3->getCode();
			 			}
			 			if ($3->isCalculated()) {
			 				opDroite = new Operand($3->getValue());
							instRes = new Instruction (OPCODE_CPY, new Operand($1->getIdentTempResult()), opDroite);
							//$1->setValue($3->getValue());
			 			} else {
			 				opDroite = new Operand($3->getIdentTempResult());
							instRes = new Instruction (OPCODE_CPY, new Operand($1->getIdentTempResult()), opDroite);
			 			}
			 			$$->add(instRes);
					}
			 	|	Call {
			 			unsupported();
					}
			 	|	BlockCode {
			 			$$ = $1;
			 		}
			 	;

ForDirection	:	KW_TO
			 	|	KW_DOWNTO
			 	;





//Expression		:	MathExpr
//			 	|	CompExpr
//			 	|	BoolExpr
//			 	|	AtomExpr
//			 	|	VarExpr
//				|	Call
//			 	;
//
//MathExpr		:	Expression OP_ADD Expression
//			 	|	Expression OP_SUB Expression
//			 	|	Expression OP_MUL Expression
//			 	|	Expression OP_SLASH Expression
//			 	|	Expression KW_DIV Expression
//			 	|	Expression KW_MOD Expression
//			 	|	Expression OP_EXP Expression
//			 	|	OP_SUB Expression %prec OP_NEG
//			 	|	OP_ADD Expression %prec OP_POS
//			 	;
//
//CompExpr		:	Expression OP_EQ Expression
//			 	|	Expression OP_NEQ Expression
//			 	|	Expression OP_LT Expression
//			 	|	Expression OP_LTE Expression
//			 	|	Expression OP_GT Expression
//			 	|	Expression OP_GTE Expression
//			 	;
//
//BoolExpr		:	Expression KW_AND Expression
//			 	|	Expression KW_OR Expression
//			 	|	Expression KW_XOR Expression
//			 	|	KW_NOT Expression
//			 	;
//AtomExpr		:	SEP_PO Expression SEP_PF
//			 	|	TOK_INTEGER
//			 	|	TOK_REAL
//			 	|	TOK_BOOLEAN
//			 	|	KW_NIL
//			 	|	TOK_STRING
//			 	;
//VarExpr			:	TOK_IDENT
//				|	TOK_IDENT SEP_CO ListIndices SEP_CF
//				|	TOK_IDENT SEP_DOT TOK_IDENT %prec OP_DOT
//				|	TOK_IDENT OP_PTR
//				;





Expression		:	MathExpr {
						$$ = $1;
					}
				|	CompExpr {
						$$ = $1;
					}
				|	BoolExpr {
						$$ = $1;
					}
				|	AtomExpr {
						$$ = $1;
					}
				|	VarExpr {
						$$ = $1;
					}
				|	Call {
						/*$$ = $1; ? */
					}
				;

MathExpr		:	Expression OP_ADD Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_SUB Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_MUL Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_SLASH Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression KW_DIV Expression {
						controler->errorMsg("Unsupported operation");
						return 1;
					}
				|	Expression KW_MOD Expression {
						controler->errorMsg("Unsupported operation");
						return 1;
					}
				|	Expression OP_EXP Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	OP_SUB Expression %prec OP_NEG {
						$$ = expressionsManager->unaryOperation($1, $2);
					}
				|	OP_ADD Expression %prec OP_POS {
						$$ = expressionsManager->unaryOperation($1, $2);
					}
				;

CompExpr		:	Expression OP_EQ Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_NEQ Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_LT Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_LTE Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_GT Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression OP_GTE Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				;

BoolExpr		:	Expression KW_AND Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression KW_OR Expression {
						$$ = expressionsManager->binaryOperation($1, $2, $3);
					}
				|	Expression KW_XOR Expression {
						controler->errorMsg("Unsupported operation"); return 1;
					}
				|	KW_NOT Expression {
						$$ = expressionsManager->unaryOperation($1, $2);
					}
				;

AtomExpr		:	SEP_PO Expression SEP_PF {
						$$ = $2;
					}
				|	TOK_INTEGER {
						$$ = expressionsManager->newExpressionFromToken(new TypeInteger(), $1);
					}
				|	TOK_REAL {
						$$ = expressionsManager->newExpressionFromToken(new TypeReal(), $1);
					}
				|	TOK_BOOLEAN {
						$$ = expressionsManager->newExpressionFromToken(new TypeBoolean(), $1);
					}
				|	KW_NIL {
						$$ = expressionsManager->newExpressionFromNil();
					}
				|	TOK_STRING {
						$$ = expressionsManager->newExpressionFromToken(new TypeString(), $1);
					}
				;

VarExprGaucheAffectation	:	TOK_IDENT {
									Symbol * symbol = symbolTable->getById($1);
									if (symbol == NULL) {
										controler->errorMsg("\"" + identTable->getName($1) + "\" non declare dans ce contexte");
										return 1;

									} else if (symbol->hasExpression()) { // et donc symbole variable ou constant ou argument, TODO symbole constant devrait être interdit aussi ici
										$$ = symbol->getExpression()->clone();

									} else {
										controler->errorMsg("Expression invalide, \"" + identTable->getName($1) + " \" n'est ni une variable, ni un paramètre formel de fonction");
										return 1;
									}
								}
							|	VarExpr SEP_CO ListIndices SEP_CF
							|	VarExpr SEP_DOT TOK_IDENT %prec OP_DOT{
									//	accès champ record, vérifier que le champ existe
									}
							|	VarExpr OP_PTR
							;
VarExpr			:	TOK_IDENT {
						Symbol * symbol = symbolTable->getById($1);
						if (symbol == NULL) {
							controler->errorMsg("\"" + identTable->getName($1) + "\" non declare dans ce contexte");
							return 1;

						} else if (symbol->hasExpression()) { // et donc symbole variable ou constant ou argument
							if (symbol->getExpression()->getValue() == NULL) {
								controler->errorMsg("Utilisation de variable non initialisee (" + identTable->getName($1) + ")");
								return 1;
							} else {
								$$ = symbol->getExpression()->clone();
							}

						} else {
							controler->errorMsg("Expression invalide, \"" + identTable->getName($1) + " \" n'est ni une constante, ni une variable, ni un paramètre de fonction");
							return 1;
						}
					}
				|	VarExpr SEP_CO ListIndices SEP_CF
				|	VarExpr SEP_DOT TOK_IDENT %prec OP_DOT{
						//	accès champ record, vérifier que le champ existe
						}
				|	VarExpr OP_PTR
				;




Call			 	:	TOK_IDENT Parameters {
						//	appel fonction/procédure, vérifier existence et nombre de paramètres
						}
				;

Parameters			:	SEP_PO ListParameters SEP_PF
				|	SEP_PO SEP_PF
				;

ListIndices			:	ListIndices SEP_COMMA Expression
				|	Expression
				;

ListParameters			:	ListParameters SEP_COMMA Expression
				|	Expression
				;

%%

